package communication.common.business.base;

import communication.common.business.util.MsgDataUtil;
import communication.common.business.util.NetSocketUtil;
import io.vertx.core.buffer.Buffer;
import io.vertx.core.datagram.DatagramPacket;
import io.vertx.core.datagram.DatagramSocket;
import io.vertx.core.json.JsonObject;
import io.vertx.core.net.NetSocket;
import io.vertx.core.net.SocketAddress;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;

import javax.annotation.PostConstruct;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicReference;

/**
 * 处理通过socket接收到的数据，解析成json格式，
 * @author mac
 */
@Data
@Slf4j
public class HandleMsgData {


    private Map<String,ModuleHandler> allHandler = new ConcurrentHashMap<>();

    private ApplicationContext applicationContext;

    public HandleMsgData(ApplicationContext context){
        this.applicationContext=context;
    }

    /**
     * 构造函数执行完之后执行init时，可能ModuleHandler结构的实例化对象还未被spring创建，所以可能导致beans中缺少数据，需要在获取时检查一次
     */
    @PostConstruct
    private void initAllHandler(){
        Map<String, ModuleHandler> beans = applicationContext.getBeansOfType(ModuleHandler.class);
        beans.values().forEach(e-> allHandler.put(e.getModuleName(),e));
    }



    private ModuleHandler getModuleHandler(String moduleName){
        if(allHandler.containsKey(moduleName)){
            return allHandler.get(moduleName);
        }

        initAllHandler();
        return allHandler.get(moduleName);
    }



    /**
     * 处理tcp的socket的通信数据
     * @param jsonObject tcp端口中的socket数据转换成的json
     * @param socketAddress 远端socket的address
     */
    public Buffer handleTcpMsg(JsonObject jsonObject, SocketAddress socketAddress) {
        // socket的数据转换为java对象 MsgData
        MsgData msgData = null;
        try{
            msgData=NetSocketUtil.jsonObject2MsgData(jsonObject);
        }catch (Exception e){
            log.warn("socket 消息转换为 msgData发生异常：{}",e.getCause().getMessage());
            log.warn("跳过模块化处理过程------>");
            return null;
        }

        return handleMsg(msgData, socketAddress);
    }



    public Buffer handleMsg(MsgData msgData, SocketAddress socketAddress) {
        Buffer buffer=null;
        ModuleHandler handler = getModuleHandler(msgData.getModule());

        // msgData是请求才返回异常
        if(handler==null){
            String errMsg="can not match handler! module:"+msgData.getModule();
            log.warn(errMsg);
            buffer = Buffer.buffer().appendString(errMsg);
        }

            try {
                Object dto = handler.doBusiness(msgData,socketAddress.hostAddress()+":"+socketAddress.port());
                // 响应值不会空，则通过socket发送消息
                if(dto !=null ){
                    msgData.setType(1);
                    msgData.setOpParam(null);
                    msgData.setResponse(dto);
                    buffer= Buffer.buffer().appendBytes(MsgDataUtil.obj2ByteArray(msgData));
                }
            }catch (Exception e) {
                e.printStackTrace();
                buffer = Buffer.buffer().appendString(e.getCause().toString());
            }

        return buffer;
    }


    /**
     * 处理udp的socket的通信数据
     * @param packet packet of socket
     */
    public Buffer handleUdpMsg(DatagramPacket packet) {
        // socket的数据转换为java对象 MsgData
        MsgData msgData = null;
        try{
            msgData=NetSocketUtil.datagramPacket2MsgData(packet);
        }catch (Exception e){
            log.warn("socket 消息转换为 msgData发生异常：{}",e.getCause().getMessage());
            log.warn("跳过模块化处理过程------>");
            return null;
        }

        return handleMsg(msgData, packet.sender());
    }


    /**
     *  处理udp的socket的通信内容，如果经过业务处理后有返回值，则从原socket发送返回值
     */
    public void handleAndSendMsg(DatagramSocket socket , DatagramPacket packet){
        log.debug("Received socket msg :[{}] , ip:{},port:{}",packet.data().toString(),packet.sender().host(),packet.sender().port());
        Buffer buffer=handleUdpMsg(packet);

        // send
        if(buffer!=null){
            NetSocketUtil.datagramSocketSend(socket,packet.sender().host(),packet.sender().port(),buffer);
        }
    }

    /**
     * 处理tcp的socket数据
     * @param socket
     */
    public void handleAndSendMsg(NetSocket socket  ){
        AtomicReference<JsonObject> msgObj = new AtomicReference<>();
        socket.handler(tcpBuffer->{
            FcrSocketAddress socketAddress = NetSocketUtil.getSocketAddress(socket.remoteAddress());
            try{
                // 对端通过socket传过来的内容可能不是json格式
                msgObj.set(tcpBuffer.toJsonObject());
            }catch (Exception e){
                log.warn("msg can not transfor jsonObj! socket:{}, msg:{}",socketAddress.getAddress() , tcpBuffer.toString());
            }

            // 如果没有正确解析成json格式，则忽略处理
            if( msgObj.get() == null ){
                return;
            }

            log.debug("Received socket msg :[{}] , socket:{}" , msgObj.get(), socketAddress);

            Buffer buffer = handleTcpMsg(msgObj.get(), socket.remoteAddress());

            // send
            NetSocketUtil.sendData(socket,buffer);
        });

    }

}
